from sklearn.datasets import load_iris, fetch_openml
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.datasets import get_data_home


def default_path():
    default_path = get_data_home()
    print("默认缓存路径:", default_path)


def knn_iris():
    """
    用KNN算法，对鸢尾花进行分类
    :return:
    """
    # 1. 获取数据集
    iris = load_iris()
    # 2. 划分数据集
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=6)
    # 3. 特征工程
    transfer = StandardScaler()
    x_train = transfer.fit_transform(x_train)
    x_test = transfer.transform(x_test)

    # 4. KNN算法预估器
    estimator = KNeighborsClassifier(n_neighbors=3)
    estimator.fit(x_train, y_train)

    # 5. 模型评估
    # 方法一：直接比对真实值和预测值
    y_predict = estimator.predict(x_test)
    print("预测结果为：\n", y_predict)
    print(f"直接比对真实值和预测值：\n{y_test == y_predict}")

    # 方法二：计算准确率
    print(f"准确率：\n{estimator.score(x_test, y_test)}")


# 手写数字识别：手写数字识别（MNIST）
def knn_digits():
    """
    手写数字识别：手写数字识别（MNIST）
    1. 加载数据
    2. 数据预处理（标准化）
    3. 训练KNN模型
    4. 评估模型
    5. 优化（选择最佳K值
    :return:
    """
    # 加载MNIST数据集
    """
    fetch_openml:
        这是scikit-learn提供的函数，用于从OpenML平台加载数据集。
        参数'mnist_784'指定要加载的数据集名称（MNIST的每个图像是784维向量，即28x28=784像素）。
        version=1表示加载第一个版本的数据集。
        as_frame=False表示返回的数据是NumPy数组（而不是Pandas DataFrame）。
    返回值:
        mnist.data (X): 特征数据，形状为(70000, 784)的NumPy数组，每一行代表一张28x28图像的像素值（展平为784维向量）。
        mnist.target (y): 标签数据，形状为(70000,)的NumPy数组，每一行是对应图像的数字标签（0-9）。
    """
    mnist = fetch_openml('mnist_784', version=1, as_frame=False, parser='auto', data_home='./data')
    X, y = mnist.data, mnist.target
    # 查看数据形状
    print("数据形状:", X.shape)  # (70000, 784) → 70000张图片，每张28×28=784像素
    print("标签形状:", y.shape)  # (70000,) → 每张图片对应的数字（0~9）

    # 显示一张图片
    plt.imshow(X[0].reshape(28, 28), cmap='gray')
    plt.title(f"标签: {y[0]}")
    plt.show()


def knn_iris_gscv():
    """
    用KNN算法，对鸢尾花进行分类，添加网格搜索和交叉验证
    :return:
    """
    # 1. 获取数据集
    iris = load_iris()
    # 2. 划分数据集
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=6)
    # 3. 特征工程：标准化
    transfer = StandardScaler()
    x_train = transfer.fit_transform(x_train)
    x_test = transfer.transform(x_test)

    # 4. KNN算法预估器
    estimator = KNeighborsClassifier()

    # 添加网格搜索和交叉验证
    param_dict = {'n_neighbors': [1, 3, 5, 7, 9, 11]}
    estimator = GridSearchCV(estimator, param_grid=param_dict, cv=10)

    estimator.fit(x_train, y_train)

    # 5. 模型评估
    # 方法一：直接比对真实值和预测值
    y_predict = estimator.predict(x_test)
    print("预测结果为：\n", y_predict)
    print(f"直接比对真实值和预测值：\n{y_test == y_predict}")

    # 方法二：计算准确率
    print(f"准确率：\n{estimator.score(x_test, y_test)}")

    print("最佳参数：\n", estimator.best_params_)
    print("最佳结果：\n", estimator.best_score_)
    print("最佳估计器：\n", estimator.best_estimator_)
    print("交叉验证结果：\n", estimator.cv_results_)


if __name__ == '__main__':
    knn_iris()
    # knn_digits()
    # knn_iris_gscv()
